用 Python 標準庫做一個本機密碼產生器:可選字元種類、長度、避免易混淆字元,一鍵複製到剪貼簿,並顯示預估強度(位元熵)。
不需安裝任何套件。
功能重點
程式碼(存成 password_gen_gui.py)
import tkinter as tk
from tkinter import ttk, messagebox
import string, secrets, math, random
SAFE_SYMBOLS = "!#$%&()*+,-./:;<=>?@[]^_{|}~" # 略去引號、反引號、反斜線
def entropy_bits(length: int, charset_size: int) -> float:
if length <= 0 or charset_size <= 1:
return 0.0
return length * math.log2(charset_size)
def strength_label(bits: float) -> str:
if bits < 40: return "弱"
if bits < 60: return "中"
if bits < 80: return "強"
return "非常強"
def build_charset(use_lower, use_upper, use_digit, use_symbol, avoid_ambiguous):
chars = ""
if use_lower: chars += string.ascii_lowercase
if use_upper: chars += string.ascii_uppercase
if use_digit: chars += string.digits
if use_symbol: chars += SAFE_SYMBOLS
if avoid_ambiguous:
for ch in "0O1lI|`'\"\\":
chars = chars.replace(ch, "")
return chars
def generate_password():
try:
length = int(len_var.get())
if length <= 0 or length > 128:
raise ValueError
except ValueError:
messagebox.showerror("輸入錯誤", "長度請輸入 1~128 的整數")
return
use_lower = lower_var.get()
use_upper = upper_var.get()
use_digit = digit_var.get()
use_symbol = symbol_var.get()
avoid = avoid_var.get()
if not (use_lower or use_upper or use_digit or use_symbol):
messagebox.showerror("設定錯誤", "請至少勾選一種字元類別")
return
charset = build_charset(use_lower, use_upper, use_digit, use_symbol, avoid)
if len(charset) < 2:
messagebox.showerror("設定錯誤", "有效字元過少,請取消「避免易混淆」或勾選更多類別")
return
# 先確保每類至少一個
buckets = []
if use_lower:
c = build_charset(True, False, False, False, avoid)
buckets.append(secrets.choice(c))
if use_upper:
c = build_charset(False, True, False, False, avoid)
buckets.append(secrets.choice(c))
if use_digit:
c = build_charset(False, False, True, False, avoid)
buckets.append(secrets.choice(c))
if use_symbol:
c = build_charset(False, False, False, True, avoid)
buckets.append(secrets.choice(c))
# 其餘隨機補齊
while len(buckets) < length:
buckets.append(secrets.choice(charset))
# 打散順序(使用安全亂數的 shuffle)
sysrand = random.SystemRandom()
sysrand.shuffle(buckets)
pwd = "".join(buckets[:length])
pwd_var.set(pwd)
bits = entropy_bits(length, len(charset))
entropy_var.set(f"預估強度:{bits:.1f} bits({strength_label(bits)})")
def copy_to_clip():
pw = pwd_var.get().strip()
if not pw:
messagebox.showinfo("提示", "尚未產生密碼")
return
root.clipboard_clear()
root.clipboard_append(pw)
root.update() # 確保離開程式仍在剪貼簿
messagebox.showinfo("已複製", "密碼已複製到剪貼簿")
def toggle_show():
pwd_entry.config(show="" if show_var.get() else "•")
# ---------------- GUI ----------------
root = tk.Tk()
root.title("密碼產生器")
main = ttk.Frame(root, padding=16); main.grid()
# 長度
ttk.Label(main, text="長度").grid(row=0, column=0, sticky="e")
len_var = tk.StringVar(value="16")
ttk.Entry(main, textvariable=len_var, width=6, justify="center").grid(row=0, column=1, sticky="w", padx=6)
# 選項
lower_var = tk.BooleanVar(value=True)
upper_var = tk.BooleanVar(value=True)
digit_var = tk.BooleanVar(value=True)
symbol_var = tk.BooleanVar(value=False)
avoid_var = tk.BooleanVar(value=True)
opt_row = ttk.Frame(main); opt_row.grid(row=1, column=0, columnspan=3, pady=6, sticky="w")
ttk.Checkbutton(opt_row, text="小寫 a-z", variable=lower_var).grid(row=0, column=0, padx=4)
ttk.Checkbutton(opt_row, text="大寫 A-Z", variable=upper_var).grid(row=0, column=1, padx=4)
ttk.Checkbutton(opt_row, text="數字 0-9", variable=digit_var).grid(row=0, column=2, padx=4)
ttk.Checkbutton(opt_row, text="符號", variable=symbol_var).grid(row=0, column=3, padx=4)
ttk.Checkbutton(opt_row, text="避免易混淆字元", variable=avoid_var).grid(row=0, column=4, padx=8)
# 生成/複製
btns = ttk.Frame(main); btns.grid(row=2, column=0, columnspan=3, pady=8)
ttk.Button(btns, text="產生", command=generate_password).grid(row=0, column=0, padx=6)
ttk.Button(btns, text="複製", command=copy_to_clip).grid(row=0, column=1, padx=6)
# 顯示密碼
pwd_var = tk.StringVar()
show_var = tk.BooleanVar(value=False)
ttk.Label(main, text="密碼").grid(row=3, column=0, sticky="e", pady=(6,2))
pwd_entry = ttk.Entry(main, textvariable=pwd_var, width=40, show="•")
pwd_entry.grid(row=3, column=1, columnspan=2, sticky="w", pady=(6,2))
ttk.Checkbutton(main, text="顯示", variable=show_var, command=toggle_show).grid(row=4, column=1, sticky="w")
# 熵/強度
entropy_var = tk.StringVar(value="預估強度:—")
ttk.Label(main, textvariable=entropy_var).grid(row=5, column=0, columnspan=3, pady=(8,0), sticky="w")
# 快捷鍵
root.bind("<Return>", lambda e: generate_password())
root.mainloop()
使用方式
python password_gen_gui.py
實作:
小提醒